<?php

class PageFactory {
	
	/**
	 * Creates a PageObject based on the tblPage-Table and returns the loaded Page
	 *
	 * @param int $pkPage
	 * @return Page
	 */
	
	static function CreatePage($pkPage) {

		$cfg  = Runtime::getConfiguration();
		$conn = MySQLConnection::getInstance();
		
		//Determine the Classtype of the Page from DB
		$sql = "SELECT p.pkPage, m.name, p.fkModuleInstance FROM " . $cfg['table_prefix'] . "Page AS p 
				LEFT JOIN " . $cfg['table_prefix'] . "ModuleInstance as mi ON mi.pkModuleInstance = p.fkModuleInstance
				LEFT JOIN " . $cfg['table_prefix'] . "Module as m ON m.pkModule = mi.fkModule
				WHERE pkPage = '$pkPage' OR friendly='$pkPage'";
		
		list($pkPage, $name, $fkModuleInstance) = $conn->quickQuery($sql);
		
		if($name=="" || $name=="Page") {
			// Page not found
			Runtime::logEvent("PageNotFound", __FILE__, __CLASS__, __FUNCTION__, __LINE__, array("pkPage"=>$pkPage));
			throw new Exception("PageNotFound");
			
		}
		
		/* New way to load the Page */
		try {
			$module = ModuleManager::getModule($name);

			if($module->getModuleControllerVersion()==2) {
				$page = $module->getPageController($fkModuleInstance, $pkPage);
				
				// Set additional Information
				$page->setPkPage($pkPage);
				$page->setModuleInstance($fkModuleInstance);
				$page->setModule($module);	
				
			}
			else {
				$page = $module->getPageController($pkPage);
			}
			
			return $page;
			
		}
		catch (eCMSException $e) {
			
			if($e->getCode()=="ModuleFileMissing") {
				Runtime::logEvent("ModuleFileNotFound", __FILE__, __CLASS__, __FUNCTION__, __LINE__);
				return new ErrorPage($pkPage);
			}
			elseif($e->getCode()=="ModuleNotFound") {
				Runtime::logEvent("ModuleNotFound", __FILE__, __CLASS__, __FUNCTION__, __LINE__);
				return new ErrorPage($pkPage);
			}
			elseif($e->getCode()=="PageControllerMissing") {
				Runtime::logEvent("PageControllerMissing", __FILE__, __CLASS__, __FUNCTION__, __LINE__);
				return new ErrorPage($pkPage);
			}
			
		}
		
		return null;
		
	}
	
	static function invokeMethod($page, PageRequest $req) {
		
		$method = $req->getMethod();
		
		if($method!="" && isset($page)) {

			//Destinguish from new 'eCMSModuleController'...
			if(is_subclass_of($page, "eCMSModuleController")) {
				
				$page->setPageRequest($req);
				
				//When invoking, there can be an Exception
				try {
					Runtime::setCurrentPage($page);
					$page->$method();
				}
				catch (eCMSPermissionException $e) {
					
					@header("Status: 403", true, 403);
					$page->logEvent("MethodNotAllowed", __FILE__, __CLASS__, __FUNCTION__, __LINE__, array("method"=>$method));
					$page = new ErrorPage($page);
					
				}
				catch (Exception $e) {
					// All other Exceptions
					trigger_error($e->getMessage());
				}
				
				
			}
			else {
				
				//Use the Method ItemRead cause global error handling (Item owns Instance owns Page)
				if($page->canItemRead()) {
					
					if($page->canInvokeMethod($method)) {
						Runtime::setCurrentPage($page);
						$page->$method();
						
					}
					else {
						
						@header("Status: 403", true, 403);
						$page->logEvent("MethodNotAllowed", __FILE__, __CLASS__, __FUNCTION__, __LINE__, array("method"=>$method));
						$page = new ErrorPage($page);
					}
					
				}
				else {
	
					header("Status: 403", true, 403);
					$page->logEvent("ItemNotAllowed", __FILE__, __CLASS__, __FUNCTION__, __LINE__);
					$page = new ErrorPage($page);
				}
			
			}
		}

		return $page;
		
	}
	
	/**
	 * Renders the given Page in HTML. If there are any NestedPages defined, they will also be rendered
	 *
	 * @param Page $page
	 */
	
	static function renderPage($page, $ignoreNestedPages=false) {
		//echo "<hr>Rendering Page: " . $page->getNavTitle() . "<br>";
		
		$cfg = Runtime::getConfiguration();
		
		//Initialize
		$smarty = new Smarty();
		$smarty->compile_dir = $cfg["paths"]["tmp"] . "/cache/smarty";
		$smarty->plugins_dir = eCMS_DIR . "/app/lib/smarty/plugins";
		
		$pageHTML = "";
		
		/*
		 * First of all, render the Page itself
		 * ====================================  
		 * */
		
		$tpl_filename = $page->getModuleName(). "_" . $page->getMethod() . ".tpl.php";
		
		/* set search path
		 * ---------------
		 * 1. Search in the Design-Path in the wwwroot-path
		 * 2. Seaecg in the Design-Path of the eCMS Installation-Path
		 * 3. Search in the module-Directory of the eCMS Installation-Path
		 * */ 
		
		$tpl_paths = array($cfg["paths"]["page"] . "/content/design/".$page->getDesignName()."/views/".$page->getModuleName(),
						   $cfg["paths"]["page"] . "/content/design/".$page->getDesignName()."/views",
						   $cfg["paths"]["page"] . "/content/design/general/views/".$page->getModuleName(),
						   $cfg["paths"]["page"] . "/content/design/general/views",
						   eCMS_DIR . "/content/design/".$page->getDesignName()."/views/".$page->getModuleName(),
						   eCMS_DIR . "/content/design/".$page->getDesignName()."/views",
						   eCMS_DIR . "/content/design/general/views/".$page->getModuleName(),
						   eCMS_DIR . "/content/design/general/views",
						   eCMS_DIR . "/module/core/".$page->getModuleName(),
						   eCMS_DIR . "/module/core/".$page->getModuleName()."/views",
						   eCMS_DIR . "/module/user/".$page->getModuleName(),
						   eCMS_DIR . "/module/user/".$page->getModuleName()."/views"
						   );
		
		$tpl_filepath = Utils::findFile($tpl_filename, $tpl_paths);

		
		if (!file_exists($tpl_filepath)) {
			@header("Status: 501", true, 501); //Not implemented.
			
			Runtime::logEvent("TplForMethodNotFound", __FILE__, __CLASS__, __FUNCTION__, __LINE__, array("tpl_paths" => $tpl_paths ,"tpl_filename" => $tpl_filename));
			$pageHTML = "View for Page '".$page->getNavTitle()."' not found. Cannot display any content. Sorry. (Was looking for: $tpl_filename)";
			//echo $tpl_path;
		}	
		else {	
			
			//echo "Using File: $tpl_filepath for rendering View of Page id=".$page->getPkPage();
			
			//Assign whole Page to Smarty
			//$smarty->assign("page", $page);
			
			//Add Page_Basic Information to Smarty
			if(is_subclass_of($page, "eCMSModuleController")) {

				$smarty->assign("Page_Title", $page->getTitle());
				$smarty->assign("Page_Text", $page->getText());
				
				$smarty->assign("Page_CreateUser", $page->getCreateUser());
				$smarty->assign("Page_CreateDate",  $page->getCreateDate());
				//$smarty->assign("Page_CreateUserRealname", $this->getCreateUserFullName());
				
				$smarty->assign("Page_ChangeUser",  $page->getChangeUser());
				$smarty->assign("Page_ChangeDate",  $page->getChangeDate());
				//$smarty->assign("Page_ChangeUserRealname", $this->getCreateUserFullName());
				
				//echo "Adding Special Smarty<br>";
				
			}
			
			
			//Assign Current user to Smarty
			$smarty->assign("Sys_CurrentUser", SecurityUser::getUser());
			
			//Add other importand things
			
			$smarty->assign("Sys_CurrentGetQuery", $_SERVER['QUERY_STRING']);
			
			//Path of Website
			$path_parts = pathinfo($_SERVER['REQUEST_URI']);
			$smarty->assign("Sys_RootFolder", rtrim($path_parts['dirname'], "/"));
			
			$smarty->assign("Sys_CurrentPageURL", "?page=".$page->getPkPage());
			
			$smarty->assign("Sys_DesignBasePath", "content/design" . "/" . $page->getDesignName());
			$smarty->assign("Sys_DesignSharedPath", $cfg["sharedDesignURL"] . "/" . $page->getDesignName());
			
			//Path in wich the Template was found
			$smarty->assign("Sys_TemplateDir", dirname($tpl_filepath));
			
			//JS Libs-Path
			$smarty->assign("Sys_JsLibsURL", $cfg['JsLibsURL']);
			$smarty->assign("Sys_SystemMessages", SecurityUser::getUser()->getSystemMessages());
			
			//Give Page a chance to add own data to smarty
			if(is_subclass_of($page, "Page")) { $page->assignDataToSmarty($smarty); }
			
			
			//Add all Data in the viewData-Variable to Smarty (use ModuleName as Prefix)
			$viewData = $page->getViewData();
			while((list($var, $value) = each($viewData))==true) {
				$smarty->assign($page->getModuleName()."_".$var, $value);
			}
			
			
			$pageHTML = $smarty->fetch($tpl_filepath);
			//echo "Rendered Page Length: " . strlen($pageHTML)." Bytes<br>";
		}		
		

		/**
		 * Do the NestedPages-Part
		 * =======================
		 */

		//Check Page for NestedPageSet
		$nps = $page->getNestedPageSet();
		
		//echo $nps->NestedPages->count();
		
		if(!$ignoreNestedPages && $nps && count($nps->NestedPages)) {
			//echo "creating page ".$page->getNavTitle()."<br>";
			//echo "NestedPageMode is: " . $page->getNestedPageMode() . "<br>";
			$pageHTML = PageFactory::renderNestedPageSet($nps, $pageHTML, $page);
			//echo "<pre>Print\n"; 	print_r($nps->NestedPages); echo "</pre>";
			}
		else {
			//echo "No nestedPages to render.";
		}
		
		
		//Check if this Page had the Mode "Include" wich means that the whole Page including all NestedPages have to Be included into the NestedPageset of the Parent
		if($page->getNestedPageMode()=="include") {
			
			//try to load the parent NestedPagesSet
			if($page->getParentPage()) {
				$nps = $page->getParentPage()->getNestedPageSet();
			}
			else {
				//try to load NestedPageSet from area
				$cfg = Runtime::getConfiguration();
				$conn = MySQLConnection::getInstance();
				
				$sql = "SELECT fkNestedPageSet, l.sysname FROM " . $cfg['table_prefix'] . "Area as a
						LEFT JOIN  " . $cfg['table_prefix'] . "PageLayout AS l ON l.pkPageLayout = a.fkPageLayout
						WHERE pkArea = '".$page->getFkArea()."'";
				
				list($fkNestedPageSet, $pageLayout) = $conn->quickQuery($sql);
				$npsl = new NestedPageSetList();
				$list = $npsl->getByPkNestedPageSet($fkNestedPageSet);
				$nps = $list->At(0);
				
			}
			
			
			if(count($nps->NestedPages)) {
				//Parent NestedPageSet is valid an can be used
				$pageHTML = PageFactory::renderNestedPageSet($nps, $pageHTML, $page, $pageLayout);
			}
			else {
				Runtime::logEvent("NoParentToIncludeNestedPageSet", __FILE__, __CLASS__, __FUNCTION__, __LINE__);
				//Error trying to include a nested Pageset into an non existing PageSet given by parentPage
			}
			
			
		}
		
		return $pageHTML;
		
	}
	
	static function renderNestedPageSet(NestedPageSet $nps, $mainPageHtml, $page, $pageLayoutName=null) {
		
		$cfg = Runtime::getConfiguration();
		
		//Initialize

		$smarty = new Smarty();
		$smarty->compile_dir = $cfg["paths"]["tmp"] . "/cache/smarty";
		$smarty->plugins_dir = eCMS_DIR . "/app/lib/smarty/plugins";
				
		//Reserve Array for NestedPages-Html
		$npHTML = array();
		
		foreach ($nps->NestedPages as $np) {
			
			// Create the Page
			// ---------------
				
			//Create PageReuest
			$method = "index";
			//print_r($np->getFields());
			//echo $np->method;
			if($np->method!=null && $np->method) { $method = $np->method; }
			$req = new PageRequest($np->fkPage, $method);
			$req->setGetVar("page", $np->fkPage);
			
			//Load Page
			$nestedPage = PageFactory::CreatePage($np->fkPage);
			
			//Apply the PageRqeust to to Page for further use...
			$nestedPage->setPageRequest($req);
			
			$nestedPage = PageFactory::invokeMethod($nestedPage, $req);
			
			$html = PageFactory::renderPage($nestedPage, true);
			
			//Save HTML in array adressed by the id set in the NestedPageSet for this NestedPage
			$npHTML["NestedPage_".$np->id] = $html;
		}
		
		
		/*
		 * Render all single NestedPage-Htmls and the "MainPage" (pageHTML) to a single HTML 
		 * string with smarty based on the layout name set in the NestedPageSet
		 */

		//Search Layout
		$tpl_filename = ($pageLayoutName!=null?$pageLayoutName:$page->getPagelayoutName()) . ".tpl.php";
		
		$tpl_paths = array($cfg["paths"]["page"] . "/content/design/".$page->getDesignName()."/layouts/".$page->getModuleName(),
						   $cfg["paths"]["page"] . "/content/design/".$page->getDesignName()."/layouts",
						   $cfg["paths"]["page"] . "/content/design/general/layouts/".$page->getModuleName(),
						   $cfg["paths"]["page"] . "/content/design/general/layouts",
						   "content/design/".$page->getDesignName()."/layouts/".$page->getModuleName(),
						   "content/design/".$page->getDesignName()."/layouts",
						   "content/design/general/layouts/".$page->getModuleName(),
						   "content/design/general/layouts"
						   );
	
		$tpl_filepath = Utils::findFile($tpl_filename, $tpl_paths);

		if (!file_exists($tpl_filepath)) {
			Runtime::logEvent("TplForLayoutNotFound", __FILE__, __CLASS__, __FUNCTION__, __LINE__, array("tpl_paths" => $tpl_paths ,"tpl_filename" => $tpl_filename));
		}
		else {
			
			//Render all Files to one HTML
			$smarty->clear_all_assign();

			$smarty->assign("Sys_DesignBasePath", "content/design" . "/" . $page->getDesignName());
			
			$smarty->assign("Page_CreateUser", Runtime::getCurrentMainPage()->getCreateUser());
			$smarty->assign("Page_CreateDate",  Runtime::getCurrentMainPage()->getCreateDate());
			$smarty->assign("Page_CreateUserRealname", Runtime::getCurrentMainPage()->getCreateUserFullName());
			
			$smarty->assign("Page_ChangeUser",  Runtime::getCurrentMainPage()->getChangeUser());
			$smarty->assign("Page_ChangeDate",  Runtime::getCurrentMainPage()->getChangeDate());
			$smarty->assign("Page_ChangeUserRealname", Runtime::getCurrentMainPage()->getCreateUserFullName());
		
			//Add the First Page-Html to Smarty
			$smarty->assign("NestedPage_Main", $mainPageHtml);
			
			//Also add the Current-Main-Page to Smarty
			$smarty->assign("MainPage", Runtime::getCurrentMainPage());
			
			//Add NestedPages
			$smarty->assign($npHTML);
			
			//Then Fetch again
			$html = $smarty->fetch($tpl_filepath);
			
		}
		
		return $html;
		
	}
	
}

?>